package editor;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.LinkedList;
import java.util.List;

import editor.menu.Button;
import editor.menu.Item;
import editor.menu.JumpList;
import editor.menu.Menu;
import editor.menu.Separator;
import game.entity.Treasure;
import game.entity.terrain.Stairs;
import game.entity.terrain.Tunnel;
import game.entity.terrain.Wall;
import game.room.Cell;
import game.room.Room;
import game.room.TerrainRenderer;

import applet.Game;
import applet.Mouse;
import applet.Screen;

/** */
public class EditorScreen extends Screen {
	/** */
	private Menu menu;
	/** */
	private TerrainRenderer terrainRenderer;
	/** */
	private Room room;
	/** */
	private List<Treasure> treasures;
	/** */
	private String toolCategory;
	/** */
	private String toolName;

	/** */
	private boolean usingTool;
	/** */
	private boolean usingEraser;
	/** */
	private int usingLayer = -1;

	/**
	 * @param game - the game object.
	 */
	public EditorScreen(final Game game) {
		super(game);
		menu = new Menu() {
			{
				int i = 0;
				final Item terrainItem = new Item("Wall");
				final JumpList terrainList = new JumpList(i) {
					{
						addItem(terrainItem);
						addItem(new Item("Stairs"));
						addItem(new Item("Tunnel"));
					}
				};
				Button terrainButton = new Button(i++, "Terrain") {
					{
						setItem(terrainItem);
						setJumpList(terrainList);
					}
				};
				addButton(terrainButton);

				final Item blockItem = new Item("Rock");
				final JumpList blockList = new JumpList(i) {
					{
						addItem(blockItem);
						addItem(new Item("Bush"));
						addItem(new Item("Stump"));
					}
				};
				Button blockButton = new Button(i++, "Block") {
					{
						setItem(blockItem);
						setJumpList(blockList);
					}
				};
				addButton(blockButton);

				final Item treasureItem = new Item("Diamond");
				final JumpList treasureList = new JumpList(i) {
					{
						addItem(treasureItem);
						addItem(new Item("Ruby"));
						addItem(new Item("Emerald"));
						addItem(new Item("Sapphire"));
						addItem(new Separator());
						addItem(new Item("Crown"));
						addItem(new Item("Goblet"));
						addItem(new Item("Ring"));
						addItem(new Item("Coin"));
					}
				};
				Button treasureButton = new Button(i++, "Treasure") {
					{
						setItem(treasureItem);
						setJumpList(treasureList);
					}
				};
				addButton(treasureButton);

				final Item potionItem = new Item("Speed");
				final JumpList potionList = new JumpList(i) {
					{
						addItem(potionItem);
						addItem(new Item("Strength"));
						addItem(new Separator());
						addItem(new Item("Health"));
						addItem(new Item("Life"));
						addItem(new Separator());
						addItem(new Item("Freeze"));
						addItem(new Item("Explosive"));
					}
				};
				Button potionButton = new Button(i++, "Potion") {
					{
						setItem(potionItem);
						setJumpList(potionList);
					}
				};
				addButton(potionButton);

				final Item monsterItem = new Item("Eyeball");
				final JumpList monsterList = new JumpList(i) {
					{
						addItem(monsterItem);
						addItem(new Item("Giant"));
						addItem(new Item("Mummy"));
						addItem(new Separator());
						addItem(new Item("Goblin"));
						addItem(new Item("Troll"));
						addItem(new Item("Dragon"));
						addItem(new Separator());
						addItem(new Item("Peasant"));
						addItem(new Item("Knight"));
						addItem(new Item("King"));
					}
				};
				Button monsterButton = new Button(i++, "Monster") {
					{
						setItem(monsterItem);
						setJumpList(monsterList);
					}
				};
				addButton(monsterButton);

				final Item themeItem = new Item("Palace");
				final JumpList themeList = new JumpList(i) {
					{
						addItem(themeItem);
						addItem(new Item("Dungeon"));
						addItem(new Item("Ruins"));
						addItem(new Item("Jungle"));
					}
				};
				Button themeButton = new Button(i++, "Theme") {
					{
						setItem(themeItem);
						setJumpList(themeList);
					}
				};
				addButton(themeButton);
			}
		};
	}

	@Override
	public final void begin() {
		room = new Room();
		terrainRenderer = new TerrainRenderer();
		for (int layer = 0; layer < Room.LAYERS; ++layer) {
			terrainRenderer.render(getGame().getCanvas(), room, layer);
		}

		treasures = new LinkedList<Treasure>();
	}

	@Override
	public final void end() {
		treasures.clear();
		treasures = null;
		terrainRenderer = null;
		room = null;
	}

	@Override
	public final void step() {
		handleMouseEvents();
	}

	/** */
	private void handleMouseEvents() {
		Mouse.Event event = getGame().getMouse().pollEvent();
		while (event != null) {
			Mouse.EventType type = event.getType();
			Mouse.Button button = event.getButton();
			Point position = event.getPosition();
			switch (type) {
			case PRESS:
				if (position.y > Menu.Y) {
					// Press was on menu
					Button b =
						menu.getButton(event.getPosition().x / Button.WIDTH);
					if (b != null) {
						// Press was on button
						switch (button) {
						case LEFT:
							// Select tool
							menu.resetButtons();
							b.setState(Button.State.PRESSED);
							menu.setJumpList(null);
							toolCategory = b.getName();
							toolName = b.getItem().getName();
							break;
						case RIGHT:
							// Show jump list
							menu.resetButtons();
							b.setState(Button.State.PRESSED);
							menu.setJumpList(b.getJumpList());
							toolCategory = b.getName();
							toolName = b.getItem().getName();
						default:
							break;
						}
					}
				} else {
					// Press was on main editor area
					JumpList jump = menu.getJumpList();
					if (jump != null) {
						if (position.y >= Menu.Y - jump.getHeight()
							&& position.x >= jump.getIndex() * Button.WIDTH
							&& position.x < (jump.getIndex() + 1)
								* Button.WIDTH) {
							// Press was on jump list
							Item item = jump.getItem(event.getPosition().y);
							if (item != null) {
								// Press was on item
								Button b = menu.getButton(jump.getIndex());
								b.setItem(item);
								menu.resetButtons();
								b.setState(Button.State.PRESSED);
								toolCategory = b.getName();
								toolName = b.getItem().getName();
								menu.setJumpList(null);
							}
						} else {
							menu.setJumpList(null);
						}
					} else {
						final int row =
							(position.y + Cell.HEIGHT / 2) / Cell.HEIGHT;
						final int col =
							(position.x + Cell.WIDTH / 2) / Cell.WIDTH;
						switch (button) {
						case LEFT:
							usingTool = true;
							useTool(row, col);
							break;
						case RIGHT:
							usingEraser = true;
							useEraser(row, col);
							break;
						default:
							break;
						}
					}
				}
				break;
			case RELEASE:
				switch (button) {
				case LEFT:
					usingTool = false;
					usingLayer = -1;
					break;
				case RIGHT:
					usingEraser = false;
					usingLayer = -1;
					break;
				default:
					break;
				}
				break;
			case MOVE:
				int i = 0;
				Button b = menu.getButton(i);
				while (b != null) {
					if (b.getState() == Button.State.HOVER) {
						b.setState(Button.State.NORMAL);
					}
					b = menu.getButton(++i);
				}
				if (position.y > Menu.Y) {
					Button b1 =
						menu.getButton(event.getPosition().x / Button.WIDTH);
					if (b1 != null && b1.getState() == Button.State.NORMAL) {
						b1.setState(Button.State.HOVER);
					}
				}
				break;
			case DRAG:
				if (menu.getJumpList() == null) {
					final int row =
						(position.y + Cell.HEIGHT / 2) / Cell.HEIGHT;
					final int col = (position.x + Cell.WIDTH / 2) / Cell.WIDTH;
					if (usingTool) {
						useTool(row, col);
					} else if (usingEraser) {
						useEraser(row, col);
					}
				}
			default:
				break;
			}

			// Get the next event
			event = getGame().getMouse().pollEvent();
		}
	}

	/**
	 * @param row - the row.
	 * @param col - the column.
	 */
	private void useTool(final int row, final int col) {
		if (0 > row || row >= Room.ROWS || 0 > col || col >= Room.COLS) {
			// Out of bounds
			return;
		}
		if (usingLayer == -1) {
			usingLayer = room.getTopLayer(row, col);
		}
		if ("Terrain".equals(toolCategory)) {
			if ("Wall".equals(toolName)) {
				room.setEntity(usingLayer, row, col, new Wall());
				terrainRenderer.render(getGame().getCanvas(), room, usingLayer);
			} else if ("Stairs".equals(toolName)) {
				room.setEntity(usingLayer, row, col, new Stairs());
				terrainRenderer.render(getGame().getCanvas(), room, usingLayer);
				if (usingLayer != 0) {
					room.setEntity(usingLayer - 1, row, col, new Stairs());
					terrainRenderer.render(getGame().getCanvas(), room,
						usingLayer - 1);
				}
			} else if ("Tunnel".equals(toolName)) {
				room.setEntity(usingLayer, row, col, new Tunnel());
				terrainRenderer.render(getGame().getCanvas(), room, usingLayer);
				if (usingLayer != 0) {
					room.setEntity(usingLayer - 1, row, col, new Tunnel());
					terrainRenderer.render(getGame().getCanvas(), room,
						usingLayer - 1);
				}
			}
		} else if ("Treasure".equals(toolCategory)) {
			try {
				Treasure treasure =
					(Treasure) Class
						.forName("game.entity.treasure." + toolName)
						.newInstance();
				treasure.setPosition(usingLayer, row, col);
				treasures.add(treasure);
			} catch (Exception e) {
				System.err.println("ERROR: Class \"game.entity.treasure."
					+ toolName + "\" could not be found.");
			}
		}
	}

	/**
	 * @param row - the row.
	 * @param col - the column.
	 */
	private void useEraser(final int row, final int col) {
		if (0 > row || row >= Room.ROWS || 0 > col || col >= Room.COLS) {
			// Out of bounds
			return;
		}
		if (usingLayer == -1) {
			usingLayer = room.getTopLayer(row, col) - 1;
			if (usingLayer == -1) {
				usingLayer = 0;
			}
		}
		room.setEntity(usingLayer, row, col, null);
		terrainRenderer.render(getGame().getCanvas(), room, usingLayer);
	}

	@Override
	public final void draw(final Graphics g) {
		// Clear screen
		final Color grass = new Color(65, 150, 70);
		g.setColor(grass);
		g.fillRect(0, 0, WIDTH, HEIGHT);

		// Draw terrain
		terrainRenderer.draw(g, 0, 0);

		// Draw cursor
		Mouse mouse = getGame().getMouse();
		if (mouse.getOnScreen() && mouse.getY() < Screen.HEIGHT - Cell.HEIGHT) {
			final int row = (mouse.getY() + Cell.HEIGHT / 2) / Cell.HEIGHT;
			final int col = (mouse.getX() + Cell.WIDTH / 2) / Cell.WIDTH;
			g.setColor(Color.GREEN);
			g.drawOval(col * Cell.WIDTH - Cell.WIDTH / 2, row * Cell.HEIGHT
				- Cell.HEIGHT / 2, Cell.WIDTH, Cell.HEIGHT);
		}

		// Draw menu
		menu.draw(g);

		// Test
		for (Treasure t : treasures) {
			t.draw(g);
		}
	}
}
